<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Acconeer API: Presence Detector</title>
<link href="tabs.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="dynsections.js"></script>
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtreedata.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
  $(document).ready(initResizable);
</script>
<link href="search/search.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="search/searchdata.js"></script>
<script type="text/javascript" src="search/search.js"></script>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  <td id="projectalign" style="padding-left: 0.5em;">
   <div id="projectname">Acconeer API
   </div>
  </td>
 </tr>
 </tbody>
</table>
</div>
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
<script type="text/javascript">
var searchBox = new SearchBox("searchBox", "search",false,'Search');
</script>
<script type="text/javascript" src="menudata.js"></script>
<script type="text/javascript" src="menu.js"></script>
<script type="text/javascript">
$(function() {
  initMenu('',true,false,'search.php','Search');
  $(document).ready(function() { init_search(); });
});
</script>
<div id="main-nav"></div>
</div><!-- top -->
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
      <div id="nav-sync" class="sync"></div>
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
$(document).ready(function(){initNavTree('presence.html','');});
</script>
<div id="doc-content">
<!-- window showing the filter options -->
<div id="MSearchSelectWindow"
     onmouseover="return searchBox.OnSearchSelectShow()"
     onmouseout="return searchBox.OnSearchSelectHide()"
     onkeydown="return searchBox.OnSearchSelectKey(event)">
</div>

<!-- iframe showing the search results (closed by default) -->
<div id="MSearchResultsWindow">
<iframe src="javascript:void(0)" frameborder="0" 
        name="MSearchResults" id="MSearchResults">
</iframe>
</div>

<div class="header">
  <div class="headertitle">
<div class="title">Presence Detector </div>  </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>The presence detector provide software to detect movement in front of the sensor, from slow movement like a person resting in a sofa to fast movement like a person walking towards the sensor. The detector is based on the Sparse service and utilize the public api.</p>
<div class="image">
<img src="RSS_stack.png" alt="RSS_stack.png"/>
</div>
<p>The detector is designed to detect movement with a low update rate to enable low power use cases as well as higher update rate to keep track of a person walking within the range of the sensor. The detector provides output data to detect movement as well as distance to where the movement occurred. This enable applications to implement smart presence algorithms and react on movement in different areas.</p>
<div class="image">
<img src="presence_intro.png" alt="presence_intro.png"/>
</div>
<p>For more details on the Presence algorithm and the Sparse service it is recommended to use our Exploration Tool. Check it out on <a href="https://github.com/acconeer/acconeer-python-exploration">GitHub</a>, <a href="https://github.com/acconeer/acconeer-python-exploration">https://github.com/acconeer/acconeer-python-exploration</a>.</p>
<p>Acconeer provides an example of how to use the presence detector: <a class="el" href="example__detector__presence_8c.html">example_detector_presence.c</a></p>
<h1>Setting up the Detector</h1>
<p>All services and detectors in the Acconeer API are created and activated in two distinct steps. In the first creation step the configuration settings are evaluated and all necessary resources are allocated. If there is some error in the configuration or if there are not enough resources in the system to run the detector, the creation step will fail. However, when the creation is successful you can be sure that the second activation step will not fail due to any configuration or resource issues. When the detector is activated the radar is activated and can start producing data.</p>
<h2>Initializing the System</h2>
<p>The Radar System Software (RSS) must be activated before any other calls are done. The activation requires a pointer to an <a class="el" href="structacc__hal__t.html" title="This struct contains the information about the sensor integration that RSS needs. ...">acc_hal_t</a> struct which contains information on the hardware integration and function pointers to hardware driver functions that are needed by RSS. See chapter 4 in the document “HAL Integration User Guide” for more information on how to integrate to the driver layer and populate the hal struct.</p>
<p>In Acconeer’s example integration towards STM32 and the drivers generated by the STM32Cube tool, there is a function acc_hal_integration_get_implementation to obtain the hal struct.</p>
<div class="fragment"><div class="line"><a class="code" href="structacc__hal__t.html">acc_hal_t</a> hal = <a class="code" href="acc__hal__integration_8h.html#a8b93eb4abdb9ad75250ca6404e0b412d">acc_hal_integration_get_implementation</a>();</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (!<a class="code" href="group__RSS.html#ga478a45b4920777d3d4fc0f5fc8d05b58">acc_rss_activate</a>(&amp;hal))</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><p>The corresponding code looks slightly different in software packages for the Raspberry Pi and other software packages from Acconeer where peripheral drivers for the host are included. The driver layer is first initialized by calling acc_driver_hal_init. The hal struct is then obtained with the function acc_driver_hal_get_implementation.</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (!acc_driver_hal_init())</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div><div class="line"></div><div class="line"><a class="code" href="structacc__hal__t.html">acc_hal_t</a> hal = acc_driver_hal_get_implementation();</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (!<a class="code" href="group__RSS.html#ga478a45b4920777d3d4fc0f5fc8d05b58">acc_rss_activate</a>(&amp;hal))</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><h2>Presence Configuration</h2>
<p>Before the presence detector can be created and activated, we must prepare a detector configuration. First a configuration is created.</p>
<div class="fragment"><div class="line"><a class="code" href="group__Presence.html#ga9d3f2fcc031e435fd11b78f8bef80728">acc_detector_presence_configuration_t</a> presence_configuration = <a class="code" href="group__Presence.html#ga9cacc6cecd96b3f07b85e7cb0900a4cc">acc_detector_presence_configuration_create</a>();</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (presence_configuration == NULL)</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><p>The newly created configuration contains default settings for all configuration parameters and can be passed directly to the acc_detector_presence_create function. However, in most scenarios there is a need to change at least some of the configuration parameters.</p>
<p>Configuration parameters are described in <a class="el" href="acc__detector__presence_8h.html">acc_detector_presence.h</a>. This user guide explains how to use the filter parameters based on use cases to detect typical fast and slow movements. It is recommended to use Exploration Tool to find settings according to the specific use case and then transfer it to an embedded application.</p>
<h3>Profiles</h3>
<p>The services and detectors support profiles with different configuration of emission in the sensor. The different profiles provide an option to configure the wavelet length and optimize on either depth resolution or radar loop gain. More information regarding profiles can be read in the <a href="https://acconeer-python-exploration.readthedocs.io/en/latest/sensor_introduction.html">sensor introduction document</a>.</p>
<div class="image">
<img src="fig_distance_resolution.png" alt="fig_distance_resolution.png"/>
</div>
<p>The figure above shows the envelope signal of the same objects with two different profiles, one with short wavelet and one with longer.</p>
<p>The presence detector supports 5 different profiles which are defined in <a class="el" href="acc__service_8h.html">acc_service.h</a>. Profile 1 has the shortest wavelet and should be used in applications which aim to see multiple objects or with short distance to the object. Profiles with higher numbers have longer wavelet and are more suitable to use in applications which aim to see objects with weak reflection or objects further away from the sensor. The highest profiles, 4 and 5, are optimized for maximum radar loop gain which leads to lower precision in the distance estimate.</p>
<p>Profiles can be configured by the application by using a set function in the detector api. The default profile is ACC_SERVICE_PROFILE_2.</p>
<div class="fragment"><div class="line"><span class="keywordtype">void</span> <a class="code" href="group__Presence.html#ga1071ad4be81a450495f3e2b5e2aedc20">acc_detector_presence_configuration_service_profile_set</a>(<a class="code" href="group__Presence.html#ga9d3f2fcc031e435fd11b78f8bef80728">acc_detector_presence_configuration_t</a> configuration,</div><div class="line">                                                             <a class="code" href="group__Generic.html#gaa281da2c8fcd709b60cfdfe2b75b888a">acc_service_profile_t</a>                 service_profile);</div></div><!-- fragment --><h2>Creating Detector</h2>
<p>After the presence detector configuration has been prepared and populated with desired configuration parameters, the actual detector instance must be created. During the creation step all configuration parameters are validated and the resources needed by RSS are reserved. This means that if the creation step is successful, we can be sure that it is possible to activate the detector and get data from the sensor (unless there is some unexpected hardware error).</p>
<div class="fragment"><div class="line"><a class="code" href="group__Presence.html#gab5e7ccca208df4118a98c62ad2efbebc">acc_detector_presence_handle_t</a> handle = <a class="code" href="group__Presence.html#ga0965c20441b4b1c0c2c2b992a974f764">acc_detector_presence_create</a>(presence_configuration);</div><div class="line"></div><div class="line"><span class="keywordflow">if</span> (handle == NULL)</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><p>If the detector handle returned from acc_detector_presence_create is equal to NULL, then some setting in the configuration made it impossible for the system to create the detector. One common reason is that the requested sweep length is too long for the selected profile, but in general, looking for error messages in the log is the best way to find out why a detector creation failed.</p>
<p>The configuration can be destroyed when the detector has been created</p>
<div class="fragment"><div class="line"><a class="code" href="group__Presence.html#gad9e0da739120c058e18a45d7ecf6aac9">acc_detector_presence_configuration_destroy</a>(&amp;presence_configuration);</div></div><!-- fragment --><p>It is now also possible to activate the detector. This means that the radar sensor may start to produce data</p>
<div class="fragment"><div class="line"><span class="keywordtype">bool</span> status = <a class="code" href="group__Presence.html#gaf999834eb955f9c01d063c6f4f095b19">acc_detector_presence_activate</a>(handle);</div></div><!-- fragment --><h2>Get Presence Detection</h2>
<p>Presence data is read from the detector by a to call to the function acc_detector_presence_get_next. This function blocks until the next sweep arrives from the sensor and the result is available in result.</p>
<div class="fragment"><div class="line"><a class="code" href="structacc__detector__presence__result__t.html">acc_detector_presence_result_t</a> result;</div><div class="line"></div><div class="line"><span class="keywordflow">for</span> (<span class="keywordtype">int</span> i = 0; i &lt; 10; i++)</div><div class="line">{</div><div class="line">        status = <a class="code" href="group__Presence.html#ga3cc3c37dc942730713fdd33729e18712">acc_detector_presence_get_next</a>(handle, &amp;result);</div><div class="line">        <span class="keywordflow">if</span> (!status)</div><div class="line">        {</div><div class="line">                <span class="comment">/* Handle error */</span></div><div class="line">        }</div><div class="line">}</div></div><!-- fragment --><h2>Reconfigure</h2>
<p>An application might want to change configuration at different points. For example low update rate when waiting for movement and higher update rate to track movement. The detector provides a function to reconfigure the detector.</p>
<div class="fragment"><div class="line"><span class="keywordflow">if</span> (!<a class="code" href="group__Presence.html#ga82e961ec9114625222f011e9d545badd">acc_detector_presence_reconfigure</a>(&amp;handle, presence_configuration))</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><p>Note that a reconfiguration will destroy and setup the sparse service with the new configuration. This operation involves deallocation and allocation of memory. The current filter state will be kept if the sweep range is unchanged, otherwise it will be reset.</p>
<h2>Deactivating and Destroying the Detector</h2>
<p>Call the acc_detector_presence_deactivate function to stop measurements.</p>
<div class="fragment"><div class="line">status = <a class="code" href="group__Presence.html#ga9b98cd8e6091fa4dfa019b221734abac">acc_detector_presence_deactivate</a>(handle);</div><div class="line"><span class="keywordflow">if</span> (!status)</div><div class="line">{</div><div class="line">        <span class="comment">/* Handle error */</span></div><div class="line">}</div></div><!-- fragment --><p>After the detector has been deactivated it can be activated again to resume measurements or it can be destroyed to free up the resources associated with the detector handle.</p>
<div class="fragment"><div class="line"><a class="code" href="group__Presence.html#ga389fa282b65ef8c2a5e95615ff78a80c">acc_detector_presence_destroy</a>(&amp;handle);</div></div><!-- fragment --><p>Finally, call acc_rss_deactivate when the application doesn’t need to access the Radar System Software anymore. This releases any remaining resources allocated in RSS.</p>
<div class="fragment"><div class="line"><a class="code" href="group__RSS.html#ga5221ed13d3d7aff540420aacfe55b5e2">acc_rss_deactivate</a>();</div></div><!-- fragment --><h2>Presence Result</h2>
<p>Presence result is provided as output from get_next() function.</p>
<div class="fragment"><div class="line"><a class="code" href="structacc__detector__presence__result__t.html">acc_detector_presence_result_t</a> result;</div><div class="line"><a class="code" href="group__Presence.html#ga3cc3c37dc942730713fdd33729e18712">acc_detector_presence_get_next</a>(handle, &amp;result);</div></div><!-- fragment --><p>One member variable gives an indication of presence or no presence. It's also possible to get more details about the movement that is detected, see <a class="el" href="structacc__detector__presence__result__t.html" title="Presence detector results container. ">acc_detector_presence_result_t</a> for more information.</p>
<h1>The Presence Data</h1>
<h2>Detecting Slower Movements &ndash; Inter-frame Deviation</h2>
<p>For every frame and depth, we take the mean sweep and feed it through a fast and a slow low pass filter.</p>
<p>The presence detection algorithm achieves this by depthwise looking at the deviation between a fast and a slow low pass filtered version of the signal. This deviation is then filtered again both in time and depth. To be more robust against changing environments and variations between sensors, a normalization is done against the noise floor.</p>
<p>The inter-frame deviation is based on the deviation between the two filters.</p>
<h2>Detecting Faster Movements &ndash; Intra-frame Deviation</h2>
<p>For every frame and depth, the intra-frame devition is based on the deviation from the mean of the sweeps.</p>
<p>Both the inter- and the intra-frame deviations are filtered both in time and depth. Also, to be more robust against changing environments and variations between sensors, a normalization is done against the noise floor. Finally, some simple processing is applied to generate the final output.</p>
<p>As previously mentioned, the inter-frame part is good at detecting slower movements, and the intra-frame part is good at detecting faster movements. By slower movements we mean, for example, a person sitting in a chair or sofa. Faster movements could be a person walking or waving their hand.</p>
<h2>Example from Exploration Tool</h2>
<p>The figure below provide an overview of the signals recieved by Exploration Tool.</p>
<div class="image">
<img src="sparse_presence.png" alt="sparse_presence.png"/>
</div>
<ul>
<li>Top plot: The frame (blue) along with the fast (orange) and slow (green) filtered mean sweep. The distance between the fast (orange) and slow (green) dots is the basis of the inter-frame part, and the spread of the sweeps (blue) is the basis of the intra-frame part.</li>
<li>Middle plot: The "depthwise presence". This signal is the time filtered, depth filtered, and normalized version of the weighted sum of the inter- and intra-frame parts. The blue and orange parts show the inter- and intra-frame contributions respectively.</li>
<li>Bottom plot: The detector output. This is obtained from taking the maximum in the above plot and low pass filtering it. The plot is limited to give a clearer view.</li>
</ul>
<h2>Common Use Cases</h2>
<p>By default, the detector is configured such that both faster and slower movements are detected. This means that both the inter- and intra-frame parts are used. We recommend this as a starting point.</p>
<p>The overall sensitivity can be adjusted with the detection_threshold parameter. If the detection toggles too often, try increasing the output_time_const parameter. If it is too sluggish, try decreasing it instead.</p>
<p>Tuning the other parameters is described in the following sections.</p>
<h3>Fast Movement</h3>
<p>Fast movements are typically looking for a person walking towards or away from the sensor</p>
<ul>
<li>Disable the inter-frame part by setting the intra_frame_weight to 1</li>
<li>intra_frame_time_const - Look at the depthwise presence (middle plot). If it can't keep up with the movements, try decreasing the time constant. Instead, if it's too flickery, try increasing the time constant. This will also be seen in the presence distance.</li>
</ul>
<p>Since the inter-frame part is disabled, inter-frame parameters have no effect.</p>
<h3>Slow Movement</h3>
<p>Slow motions are typcally looking for a person resting in a sofa</p>
<ul>
<li>Disable the intra-frame part by setting the intra_frame_weight to 0.</li>
<li>inter_frame_fast_cutoff - If too low, some (too fast) motions might not be detected. If too high, unnecessary noise might be entered into the detector. Values larger than half the update_rate disables this filter. If that is not enough, you need a higher update_rate or use intra-frame part.</li>
<li>inter_frame_slow_cutoff - If too high, some (too slow) motions might not be detected. If too low, unnecessary noise might be entered into the detector, and changes to the static environment takes a long time to adjust to.</li>
<li>inter_frame_deviation_time_const - This behaves in the same way as the intra-frame time constant. Look at the depthwise presence (middle plot). If it can't keep up with movements changing depth, try decreasing the time constant. Instead, if it's too flickery, try increasing the time constant.</li>
</ul>
<p>Since the intra-frame part is disabled, the intra_frame_time_const has no effect. </p>
</div></div><!-- contents -->
</div><!-- doc-content -->
<!-- start footer part -->
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
  <ul>
    <li class="navelem"><a class="el" href="md__home_ai_jenkins_workspace_sw-main_0D2_doc_user_guides_rss_user_guide_main.html">User guides</a></li>
    <li class="footer">Generated on Mon Dec 2 2019 09:40:46 for Acconeer API by
    <a href="http://www.doxygen.org/index.html">
    <img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.13 </li>
  </ul>
</div>
</body>
</html>
